package com.xnyzc.lhy.finance.service.impl.cashwithdrawal;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xnyzc.lhy.common.entity.Rv;
import com.xnyzc.lhy.common.exception.PangException;
import com.xnyzc.lhy.common.global.Configuration;
import com.xnyzc.lhy.common.penum.EErrorCode;
import com.xnyzc.lhy.common.util.CheckUtil;
import com.xnyzc.lhy.common.util.DateUtil;
import com.xnyzc.lhy.common.util.IDUtil;
import com.xnyzc.lhy.common.util.TokenUtil;
import com.xnyzc.lhy.finance.constant.*;
import com.xnyzc.lhy.finance.constant.redis.RedisKeyConstant;
import com.xnyzc.lhy.finance.entity.bank.OaDBindBankCard;
import com.xnyzc.lhy.finance.entity.bank.OaSysCpBank;
import com.xnyzc.lhy.finance.entity.bill.OaDBill;
import com.xnyzc.lhy.finance.entity.cashwithdrawal.OaDCashWithdrawal;
import com.xnyzc.lhy.finance.mapper.bank.OaDBindBankCardMapper;
import com.xnyzc.lhy.finance.mapper.cashwithdrawal.OaDCashWithdrawalMapper;
import com.xnyzc.lhy.finance.mapper.wallet.OaDWalletMapper;
import com.xnyzc.lhy.finance.params.dto.cashwithdrawal.OaCashWithdrawalRecordDTO;
import com.xnyzc.lhy.finance.params.vo.bill.OaDriverInfoFiledVO;
import com.xnyzc.lhy.finance.params.vo.cashdrawal.OaCashWithdrawalDetialVO;
import com.xnyzc.lhy.finance.params.vo.cashdrawal.OaCashWithdrawalInfoVO;
import com.xnyzc.lhy.finance.params.vo.cashdrawal.OaCashWithdrawalVO;
import com.xnyzc.lhy.finance.service.bill.IOaDBillService;
import com.xnyzc.lhy.finance.service.cashwithdrawal.IOaDCashWithdrawalService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xnyzc.lhy.finance.service.config.IOaSysCashWithdrawalConfigService;
import com.xnyzc.lhy.finance.service.fegin.cp.IFinanceTradeService;
import com.xnyzc.lhy.finance.service.fegin.message.FeignMessageService;
import com.xnyzc.lhy.finance.service.fegin.oss.FeginOssService;
import com.xnyzc.lhy.finance.service.wallet.IOaDWalletRecordService;
import com.xnyzc.lhy.finance.service.wallet.IOaDWalletService;
import com.xnyzc.lhy.finance.utils.HiddenUtil;
import com.xnyzc.lhy.finance.entity.wallet.OaDWallet;
import com.xnyzc.lhy.finance.entity.config.OaSysCashWithdrawalConfig;
import com.xnyzc.lhy.order.entity.user.message.OaSysMessage;
import com.xnyzc.lhy.resource.common.cp.dto.BizInfo;
import com.xnyzc.lhy.resource.common.cp.dto.PayAccountInfo;
import com.xnyzc.lhy.resource.common.cp.dto.RecAccountInfo;
import com.xnyzc.lhy.resource.common.cp.dto.TransactionInfo;
import com.xnyzc.lhy.resource.common.cp.penum.CurrencyCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 司机提现表 服务实现类
 * </p>
 *
 * @author cuixiaojian
 * @since 2019-10-16
 */
@Slf4j
@Service
public class OaDCashWithdrawalServiceImpl extends ServiceImpl<OaDCashWithdrawalMapper, OaDCashWithdrawal> implements IOaDCashWithdrawalService {

    /**
     * 提现处理状态 成功
     */
    private final Integer SUCCESS = 1;
    /**
     * 提现处理状态 失败
     */
    private final Integer ERROR = 0;
    /**
     * 提现处理状态 未进行
     */
    private final Integer NOING = 2;

    // 正式商户号
    private final String merId = "808080211308382";

    // 测试商户号
    // private final String merId = "000091911048477";

    @Value("${global.withdraw.cash}")
    private boolean withdrawalOff;

    @Value("${global.withdraw.comment}")
    private String withdrawalComment;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private OaDCashWithdrawalMapper oaDCashWithdrawalMapper;

    @Autowired
    private OaDWalletMapper oaDWalletMapper;

    @Autowired
    private OaDBindBankCardMapper oaDBindBankCardMapper;

    @Autowired
    private IOaDWalletRecordService iOaDWalletRecordService;

    @Autowired
    private IOaSysCashWithdrawalConfigService iOaSysCashWithdrawalConfigService;

    @Autowired
    private FeginOssService feginOssService;

    @Autowired
    private IOaDBillService iOaDBillService;

    @Autowired
    private FeignMessageService feignMessageService;

    @Autowired
    private IFinanceTradeService iFinanceTradeService;

    @Autowired
    private IOaDWalletService iOaDWalletService;

    /**
     * 获取提现记录
     * @param oaCashWithdrawalRecordDTO 司机ID
     * @return List
     */
    @Override
    public Rv getCashDrawalRecord(OaCashWithdrawalRecordDTO oaCashWithdrawalRecordDTO) {

        if (CheckUtil.objIsEmpty(oaCashWithdrawalRecordDTO.getDriverId()) || CheckUtil.objIsEmpty(oaCashWithdrawalRecordDTO.getPage())) {
            log.info(oaCashWithdrawalRecordDTO.toString());
            throw PangException.create(EErrorCode.missingArg);
        }

        if (CheckUtil.objIsEmpty(oaCashWithdrawalRecordDTO.getLimit())) {
            oaCashWithdrawalRecordDTO.setLimit(3L);
        }

        try {

            List<OaCashWithdrawalVO> oaCashWithdrawalVOList= oaDCashWithdrawalMapper.queryDriverCashWithdrawalRecord(oaCashWithdrawalRecordDTO);

            return Rv.wrap(oaCashWithdrawalVOList);

        } catch (Exception e) {
            log.error(e.getMessage());
            throw PangException.create(EErrorCode.unkown);
        }
    }

    /**
     * 获取提现详情
     * @param cashId 提现ID
     * @return Object
     */
    @Override
    public Rv getCashWithdrawalInfo(Long cashId) {

        OaCashWithdrawalInfoVO oaDCashWithdrawal = null;

        try {
            oaDCashWithdrawal = oaDCashWithdrawalMapper.queryDriverCashWithdrawalInfo(cashId);

            // 截取银行卡后四位
            oaDCashWithdrawal.setWithdrawalBankCardNumber(HiddenUtil.bankCardBuffer(oaDCashWithdrawal.getWithdrawalBankCardNumber()));

        } catch (Exception e) {
            log.error(e.getMessage());
            throw PangException.create(EErrorCode.unkown);
        }

        List<OaDriverInfoFiledVO> cashStatusList = new ArrayList<>();
        for (int i = 0; i < 3; i++) {
            OaDriverInfoFiledVO oavo = new OaDriverInfoFiledVO();
            switch (i) {
                case 0:
                    oavo.setDescText("发起提现申请");
                    oavo.setValue(DateUtil.convertDateToStringMonthDay(oaDCashWithdrawal.getCreateTime()));
                    oavo.setStatus(SUCCESS);
                    break;
                case 1:
                    oavo.setDescText("银行处理中");
                    oavo.setValue(DateUtil.convertDateToStringMonthDay(oaDCashWithdrawal.getCreateTime()));
                    if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.FILED) {
                        oavo.setStatus(ERROR);
                    } else if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.PUT_CASH_WITHDRAWAL_APPLY) {
                        oavo.setStatus(NOING);
                    } else {
                        oavo.setStatus(SUCCESS);
                    }
                    break;
                case 2:
                    oavo.setDescText("交易成功");

                    if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.FILED) {
                        oavo.setStatus(ERROR);
                        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime())) {
                            oavo.setValue(DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime()));
                            oavo.setDescText("交易失败");
                        } else {
                            oavo.setValue("");
                        }
                    } else if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.PUT_CASH_WITHDRAWAL_APPLY) {
                        oavo.setStatus(NOING);
                        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime())) {
                            oavo.setValue("预计" + DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime()) + "前");
                        } else {
                            oavo.setValue("");
                        }
                    } else if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.CASH_WITHDRAWAL_HANDLE) {
                        oavo.setStatus(NOING);
                        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime())) {
                            oavo.setValue("预计" + DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime()) + "前");
                        } else {
                            oavo.setValue("");
                        }
                    } else if (oaDCashWithdrawal.getWithdrawalProgress() == CashWithdrawalConstant.HANDLE_SUCCESS) {
                        oavo.setStatus(SUCCESS);
                        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime())) {
                            if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalArrivalTime())) {
                                oavo.setValue(DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalArrivalTime()) + "到账");
                            } else {
                                oavo.setValue(DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime()) + "到账");
                            }
                        } else {
                            oavo.setValue("");
                        }
                    } else {
                        oavo.setStatus(NOING);
                        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime())) {
                            oavo.setValue("预计" + DateUtil.convertDateToString(oaDCashWithdrawal.getWithdrawalEstimatedArrivalTime()) + "前");
                        } else {
                            oavo.setValue("");
                        }
                    }

                    break;

                default:
                    break;
            }
            cashStatusList.add(oavo);
            oavo = null;

        }

        // 以下为拼装集合过程
        List<OaDriverInfoFiledVO> oaDriverCashWithdrawalInfoFiledVOList = new ArrayList<>();

        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalAmount())) {
            OaDriverInfoFiledVO oaDriverBillInfoFiledVO = new OaDriverInfoFiledVO();
            oaDriverBillInfoFiledVO.setDescText("提现金额");
            oaDriverBillInfoFiledVO.setValue(oaDCashWithdrawal.getWithdrawalAmount().toString());
            oaDriverCashWithdrawalInfoFiledVOList.add(oaDriverBillInfoFiledVO);
            oaDriverBillInfoFiledVO = null;
        }
        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getCreateTime())) {
            OaDriverInfoFiledVO oaDriverBillInfoFiledVO = new OaDriverInfoFiledVO();
            oaDriverBillInfoFiledVO.setDescText("提现时间");
            oaDriverBillInfoFiledVO.setValue(DateUtil.convertDateToString(oaDCashWithdrawal.getCreateTime()));
            oaDriverCashWithdrawalInfoFiledVOList.add(oaDriverBillInfoFiledVO);
            oaDriverBillInfoFiledVO = null;
        }
        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getBank()) && CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalBankCardNumber())) {
            OaDriverInfoFiledVO oaDriverBillInfoFiledVO = new OaDriverInfoFiledVO();
            oaDriverBillInfoFiledVO.setDescText("提现账户");
            oaDriverBillInfoFiledVO.setValue(oaDCashWithdrawal.getBank() + " (" + oaDCashWithdrawal.getWithdrawalBankCardNumber() + ")");
            oaDriverCashWithdrawalInfoFiledVOList.add(oaDriverBillInfoFiledVO);
            oaDriverBillInfoFiledVO = null;
        }
        if (CheckUtil.objIsNotEmpty(oaDCashWithdrawal.getWithdrawalComment())) {
            OaDriverInfoFiledVO oaDriverBillInfoFiledVO = new OaDriverInfoFiledVO();
            oaDriverBillInfoFiledVO.setDescText("提现备注");
            oaDriverBillInfoFiledVO.setValue(oaDCashWithdrawal.getWithdrawalComment());
            oaDriverCashWithdrawalInfoFiledVOList.add(oaDriverBillInfoFiledVO);
            oaDriverBillInfoFiledVO = null;
        }

        if (CheckUtil.objIsEmpty(oaDCashWithdrawal)) {
            throw PangException.create(EErrorCode.unCashWithdrawalInfo);
        }

        oaDCashWithdrawal.setOaDriverInfoFiledVOList(oaDriverCashWithdrawalInfoFiledVOList);

        System.gc();

        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("amount", oaDCashWithdrawal.getWithdrawalAmount().toString());
        resultMap.put("status", oaDCashWithdrawal.getWithdrawalProgress());
        resultMap.put("statusText", oaDCashWithdrawal.getLabel());
        resultMap.put("oaDriverStatusList", cashStatusList);
        resultMap.put("oaDriverInfoFiledVOList", oaDCashWithdrawal.getOaDriverInfoFiledVOList());

        return Rv.wrap(resultMap);

    }

    /**
     * 获取持卡人、银行卡、可提现金额等信息
     * @param driverId 司机ID
     * @return Object
     */
    @Override
    public Rv getCashWithdrawalDetial(Long driverId) {

        OaCashWithdrawalDetialVO oaCashWithdrawalDetialVO = null;

        try {
            oaCashWithdrawalDetialVO = oaDCashWithdrawalMapper.queryCashWithdrawalDetial(driverId);
        } catch (Exception e) {
            log.error(e.getMessage());
            throw PangException.create(EErrorCode.unkown);
        }

        if (CheckUtil.objIsEmpty(oaCashWithdrawalDetialVO)) {
            log.error("为检查到此用户:{}的银行卡信息", driverId);
            throw PangException.create(EErrorCode.walletExistTwo);
        }

        // 设置银行卡
        oaCashWithdrawalDetialVO.setBankCardNumber(HiddenUtil.bankCardBuffer(oaCashWithdrawalDetialVO.getBankCardNumber()));

        // 设置姓名
        oaCashWithdrawalDetialVO.setDriverName(HiddenUtil.nameBuffer(oaCashWithdrawalDetialVO.getDriverName()));

        OaSysCashWithdrawalConfig config =iOaSysCashWithdrawalConfigService.getCashWithdrawalConfig(driverId);
        if(CheckUtil.objIsEmpty(config)){
            throw PangException.create(EErrorCode.notConfigured);
        }
        Integer maxNumPerDay = config.getMaxNumPerDay();

        String cashText = oaDBindBankCardMapper.getType("cash_config_comment").get("label");

        StringBuilder stringBuilder = new StringBuilder(cashText);
        stringBuilder.replace(cashText.indexOf('%'), cashText.indexOf('%') + 1, maxNumPerDay.toString());

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("name", oaCashWithdrawalDetialVO.getDriverName());
        resultMap.put("bankCardNumber", "尾号" + oaCashWithdrawalDetialVO.getBankCardNumber() + "储蓄卡");
        resultMap.put("bank", oaCashWithdrawalDetialVO.getBank());
        resultMap.put("cashWithdrawalBalance", oaCashWithdrawalDetialVO.getCashBalance().toString());
        resultMap.put("cashConfigComment", stringBuilder.toString());
        if (CheckUtil.objIsEmpty(oaCashWithdrawalDetialVO.getIcon())) {
            resultMap.put("icon", "");
        } else {
            resultMap.put("icon", ((Map)feginOssService.getFileUrl(oaCashWithdrawalDetialVO.getIcon()).getData()).get("fileUrl").toString());
        }

        return Rv.wrap(resultMap);
    }

    /**
     * 提现
     * @param driverId 司机ID
     * @param amount 提现金额
     * @return Map
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Rv driverCashWithdrawal(Long driverId, BigDecimal amount) {

        // 幂等验证
        this.concurrentExistence(driverId);

        // 提现效验
        this.checkCashlegitimate(amount, driverId);

        // 提现规则获取
        OaSysCashWithdrawalConfig oaSysCashWithdrawalConfig = this.getCashRule(driverId);

        // 检查提现次数
        this.checkCashCount(driverId, oaSysCashWithdrawalConfig);

        // 检查可提现金额
        boolean allowCash = this.checkCashBalance(driverId, amount, oaSysCashWithdrawalConfig);

        if (allowCash) {
            // 检索银行卡信息
            OaDBindBankCard oaDBindBankCard = this.getBindBankCard(driverId);

            // 查询用户城市信息
            Map<String, String> cityMap = this.getUserCity(driverId);

            // 基本信息
            Date date = new Date();
            String tag  = TokenUtil.getTag();
            Long cashId = IDUtil.nextId();

            // 检索钱包版本
            OaDWallet oaDWalletVersion = this.getOaDWalletVersion(driverId);
            // 执行修改钱包金额
            String remark = this.updateWallet(oaDWalletVersion, driverId, amount, date);

            OaDCashWithdrawal oaDCashWithdrawal = new OaDCashWithdrawal();
            JSONObject singleTradeResult = this.chinaPay(oaDBindBankCard, cityMap, driverId, amount);

            if ("0".equals(singleTradeResult.get("errCode"))) {

                // 成功
                JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(singleTradeResult.get("data")));
                // 提现单号
                oaDCashWithdrawal.setWithdrawalNumber(jsonObject.get("orderNo").toString());
                // 提现状态
                oaDCashWithdrawal.setWithdrawalProgress(CashWithdrawalConstant.HANDLE_SUCCESS);
                // 到账时间
                oaDCashWithdrawal.setWithdrawalArrivalTime(new Date());

                // 保存钱包变动日志
                Integer walletRecordResult = iOaDWalletRecordService.saveWalletRecord(driverId, amount, date, BehalfConstant.CASH_OUT, oaDCashWithdrawal.getWithdrawalNumber(), remark, tag);
                // 账单保存
                this.saveBill(driverId, amount, tag);
                // 消息发送
                this.sendMessage(driverId, tag);
            } else {
                // 失败
                oaDCashWithdrawal.setWithdrawalProgress(CashWithdrawalConstant.FILED);
            }

            oaDCashWithdrawal.setWithdrawalId(cashId);
            oaDCashWithdrawal.setWithdrawalOriginator(driverId);
            oaDCashWithdrawal.setWithdrawalBank(oaDBindBankCard.getBank());
            oaDCashWithdrawal.setWithdrawalBankCardNumber(oaDBindBankCard.getBankCardNumber());
            oaDCashWithdrawal.setWithdrawalAmount(amount);
            oaDCashWithdrawal.setWithdrawalEstimatedArrivalTime(DateUtil.dateAddDays(date, 1));
            oaDCashWithdrawal.setWithdrawalComment("若提现失败，资金将原路返回");
            oaDCashWithdrawal.setCityCode(cityMap.get("adcode"));
            oaDCashWithdrawal.setTag(tag);
            oaDCashWithdrawal.setCreateUser(driverId);
            oaDCashWithdrawal.setCreateTime(date);
            oaDCashWithdrawal.setUpdateUser(driverId);
            oaDCashWithdrawal.setUpdateTime(date);

            Integer result = oaDCashWithdrawalMapper.insert(oaDCashWithdrawal);
            this.endRequest(driverId);
            return this.returnResult(result, oaDCashWithdrawal);
        } else {
            throw PangException.create(EErrorCode.cashWithdrawalAmountGTAmount);
        }
    }

    /**
     * 判断是否存在并发请求
     */
    private void concurrentExistence(Long driverId) {
        if (redisTemplate.hasKey(RedisKeyConstant.DRIVER_CASH_CLICK + driverId)) {
            throw PangException.create(EErrorCode.clickCashErr);
        }
        redisTemplate.opsForValue().set(RedisKeyConstant.DRIVER_CASH_CLICK + driverId, 1, 10, TimeUnit.SECONDS);
    }

    /**
     * 结束并发请求
     */
    private void endRequest(Long driverId) {
        redisTemplate.delete(RedisKeyConstant.DRIVER_CASH_CLICK + driverId);
    }

    /**
     * 提现效验
     */
    private void checkCashlegitimate(BigDecimal amount, Long driverId) {

        // 提现开关
        if (!withdrawalOff) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cashFiled, withdrawalComment);
        }

        if (amount.compareTo(BigDecimal.valueOf(1.00)) == -1) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cashWithdrawalAmountLtOne);
        }

        Calendar ca=Calendar.getInstance();
        ca.setTime(new Date());
        int k=ca.get(Calendar.DAY_OF_WEEK);

        if( k!=2 && k!=5){
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.weekWithdrawalError);
        }

        if(!DateUtil.timeIsRange(Configuration.WITHDRAWAL_START, Configuration.WITHDRAWAL_END)){
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.weekWithdrawalError);
        }
    }

    /**
     * 获取提现规则
     */
    private OaSysCashWithdrawalConfig getCashRule(Long driverId) {

        OaSysCashWithdrawalConfig oaSysCashWithdrawalConfig = iOaSysCashWithdrawalConfigService.getCashWithdrawalConfig(driverId);

        if (CheckUtil.objIsEmpty(oaSysCashWithdrawalConfig)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cityNotFoundCashConfig);
        }

        return oaSysCashWithdrawalConfig;
    }

    /**
     * 检查可提现次数以及钱包状态
     */
    private void checkCashCount(Long driverId, OaSysCashWithdrawalConfig oaSysCashWithdrawalConfig) {

        QueryWrapper<OaDWallet> oaDWalletQueryWrapper = new QueryWrapper<>();
        oaDWalletQueryWrapper.eq(OaDWallet.DRIVER_ID, driverId);
        oaDWalletQueryWrapper.select(OaDWallet.CASH_COUNT, OaDWallet.LOGON_STATUS);
        OaDWallet oaDWallet = oaDWalletMapper.selectOne(oaDWalletQueryWrapper);

        if (CheckUtil.objIsEmpty(oaDWallet)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.userDetailMissingErr);
        }

        if (oaDWallet.getLogonStatus() != 0) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.logonSealUp);
        }

        if (oaDWallet.getCashCount() >= oaSysCashWithdrawalConfig.getMaxNumPerDay()) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.todayDontCashWithdrawal);
        }

    }

    /**
     * 检查可提现金额
     */
    private boolean checkCashBalance(Long driverId, BigDecimal amount, OaSysCashWithdrawalConfig oaSysCashWithdrawalConfig) {
        // 检索可提现余额
        QueryWrapper<OaDWallet> oaDWalletQueryWrapper = new QueryWrapper<>();
        oaDWalletQueryWrapper.eq(OaDWallet.DRIVER_ID,driverId);
        oaDWalletQueryWrapper.select(OaDWallet.CASH_BALANCE);

        OaDWallet oaDWallet = oaDWalletMapper.selectOne(oaDWalletQueryWrapper);

        if (CheckUtil.objIsEmpty(oaDWallet)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.unWalletInfo);
        }

        if (CheckUtil.objIsEmpty(oaDWallet.getCashBalance())) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cashWithdrawalAmountErr);
        }

        if (amount.compareTo(oaSysCashWithdrawalConfig.getMaxPrice()) == 1) {
            // 如果提现金额大于次可提现金额
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cashWithdrawalConfigFiled);
        }

        return oaDWallet.getCashBalance().compareTo(amount) > -1;
    }

    /**
     * 检索银行卡号码
     */
    private OaDBindBankCard getBindBankCard(Long driverId) {

        // 检索银行卡号码
        QueryWrapper<OaDBindBankCard> oaDBindBankCardQueryWrapper = new QueryWrapper<>();
        oaDBindBankCardQueryWrapper.eq(OaDBindBankCard.DRIVER_ID, driverId);
        oaDBindBankCardQueryWrapper.eq(OaDBindBankCard.IS_USED, BankCardConstant.IS_USED);
        oaDBindBankCardQueryWrapper.select(
                OaDBindBankCard.BANK_CARD_ID,
                OaDBindBankCard.BANK,
                OaDBindBankCard.BANK_CARD_NAME,
                OaDBindBankCard.BANK_CARD_NUMBER,
                OaDBindBankCard.BANK_CARD_PHONE
        );
        OaDBindBankCard oaDBindBankCard = oaDBindBankCardMapper.selectOne(oaDBindBankCardQueryWrapper);

        if (CheckUtil.objIsEmpty(oaDBindBankCard)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.notFoundBankCard);
        }

        return oaDBindBankCard;
    }

    /**
     * 银联代付
     */
    @Transactional(rollbackFor = Exception.class)
    JSONObject chinaPay(OaDBindBankCard oaDBindBankCard, Map<String, String> cityMap, Long driverId, BigDecimal amount) {
        // 银联代付
        TransactionInfo transactionInfo = new TransactionInfo();
        // 付款方信息
        PayAccountInfo payAccountInfo = new PayAccountInfo();
        payAccountInfo.setPayAccNoCurrType(CurrencyCode.CNY.code);
        // 收款方信息
        RecAccountInfo recAccountInfo = new RecAccountInfo();
        recAccountInfo.setRecAccNo(oaDBindBankCard.getBankCardNumber());
        recAccountInfo.setRecAccName(oaDBindBankCard.getBankCardName());
        recAccountInfo.setRecAccNoCurrType(CurrencyCode.CNY.code);

        // 查询银行code码
        OaSysCpBank oaSysCpBank = oaDBindBankCardMapper.queryCodeByBankId(oaDBindBankCard.getBank());

        if (CheckUtil.objIsEmpty(oaSysCpBank)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.NOT_FOUND_BANK_CODE);
        }

        recAccountInfo.setRecBranchName(oaSysCpBank.getBankName());
        recAccountInfo.setRecBankName(oaSysCpBank.getBankCode());

        recAccountInfo.setRecProvinceName(cityMap.get("parent"));
        recAccountInfo.setRecCityName(cityMap.get("city"));
        // 用户信息
        BizInfo bizInfo = new BizInfo();
        bizInfo.setUserId(String.valueOf(driverId));
        // 公共信息
        transactionInfo.setProp(false);
        transactionInfo.setMerId(merId);
        transactionInfo.setPayAmt(Long.parseLong(amount.multiply(new BigDecimal(100)).stripTrailingZeros().toPlainString()));
        transactionInfo.setSummary("发起提现");
        transactionInfo.setPayAccInfo(payAccountInfo);
        transactionInfo.setRecAccInfo(recAccountInfo);
        transactionInfo.setBizInfo(bizInfo);
        JSONObject singleTradeResult = iFinanceTradeService.singleTrade(transactionInfo);

        log.info("JSON返回结果,{}", singleTradeResult.toJSONString());

        return singleTradeResult;
    }

    /**
     * 查询钱包版本信息
     */
    private OaDWallet getOaDWalletVersion(Long driverId) {
        QueryWrapper<OaDWallet> updateWrapper = new QueryWrapper<>();
        updateWrapper.eq(OaDWallet.DRIVER_ID, driverId);
        updateWrapper.select(OaDWallet.WALLET_ID, OaDWallet.VERSION, OaDWallet.WALLET_BALANCE, OaDWallet.CASH_BALANCE, OaDWallet.CASHING_BALANCE, OaDWallet.CASH_TOTAL, OaDWallet.CASH_COUNT);
        OaDWallet oaDWalletVersion = oaDWalletMapper.selectOne(updateWrapper);

        if (CheckUtil.objIsEmpty(oaDWalletVersion)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.unWalletInfo);
        }

        if (CheckUtil.objIsEmpty(oaDWalletVersion.getVersion()) || CheckUtil.objIsEmpty(oaDWalletVersion.getWalletBalance()) || CheckUtil.objIsEmpty(oaDWalletVersion.getCashingBalance())) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.unWalletInfo);
        }
        return oaDWalletVersion;
    }

    /**
     * 执行钱包余额修改
     */
    @Transactional(rollbackFor = Exception.class)
    String updateWallet(OaDWallet oaDWalletVersion, Long driverId, BigDecimal amount, Date date) {

        // 可提现余额
        BigDecimal cashWithdrawalAmount = oaDWalletVersion.getCashBalance();
        // 提现中余额
        BigDecimal cashingWithdrawalAmount = oaDWalletVersion.getCashingBalance();
        // 钱包余额
        BigDecimal walletAmount = oaDWalletVersion.getWalletBalance();
        // 提现总额
        BigDecimal cashTotal = oaDWalletVersion.getCashTotal();

        oaDWalletVersion.setCashBalance(cashWithdrawalAmount.subtract(amount));
        oaDWalletVersion.setCashTotal(cashTotal.add(amount));
        oaDWalletVersion.setWalletBalance(walletAmount.subtract(amount));
        // + 1 提现次数
        oaDWalletVersion.setCashCount(oaDWalletVersion.getCashCount() + 1);

        oaDWalletVersion.setUpdateUser(driverId);
        oaDWalletVersion.setUpdateTime(date);

        Integer updateResult = oaDWalletMapper.updateById(oaDWalletVersion);

        if (updateResult > 0) {

            String remark = "司机:" + driverId + "发起提现," +
                    "钱包原可提现金额:" + cashWithdrawalAmount + "元，" +
                    "原提现中金额：" + cashingWithdrawalAmount + "元，" +
                    "原余额:" + walletAmount + "元，" +
                    "现可提现金额：" + oaDWalletVersion.getCashBalance() + "元，" +
                    "现提现中金额：" + oaDWalletVersion.getCashingBalance() + "元，" +
                    "现余额：" + oaDWalletVersion.getWalletBalance();

            log.info(remark);

            return remark;

        } else {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cashFiled);
        }
    }

    /**
     * 账单保存
     */
    private void saveBill(Long driverId, BigDecimal amount, String tag) {
        // 保存账单记录
        OaDBill oaDBill = new OaDBill();
        oaDBill.setDriverId(driverId);
        oaDBill.setBillAmount(amount);
        oaDBill.setBillType(BillConstant.EXPEND);
        oaDBill.setBillTypeDesc("6");
        oaDBill.setLogonTag(1);
        oaDBill.setTag(tag);
        iOaDBillService.saveDriverBill(oaDBill);
    }

    /**
     * 消息发送
     */
    private void sendMessage(Long driverId, String tag) {
        // 发送消息
        OaSysMessage oaSysMessage = new OaSysMessage();
        oaSysMessage.setPushCode("cashWithdrawalApply");
        oaSysMessage.setDriverId(driverId);
        oaSysMessage.setTag(tag);
        oaSysMessage.setMessageType(2);
        // 设置推送内容
        oaSysMessage.setMessageContent(MessageConstant.CASH_WITHDRAWAL_APPLY);
        feignMessageService.saveMessage(oaSysMessage);
    }

    /**
     * 用户城市信息查询
     */
    private Map<String, String> getUserCity(Long driverId) {
        Map<String, String> cityMap = oaDCashWithdrawalMapper.queryDriverCity(driverId);

        if (CheckUtil.mapIsEmpty(cityMap)) {
            this.endRequest(driverId);
            throw PangException.create(EErrorCode.cityNotFound);
        }

        return cityMap;
    }

    /**
     * 提现结果
     */
    @Transactional(rollbackFor = Exception.class)
    Rv returnResult(Integer result, OaDCashWithdrawal oaDCashWithdrawal) {
        if (result > 0) {
            if (oaDCashWithdrawal.getWithdrawalProgress().equals(CashWithdrawalConstant.FILED)) {
                throw PangException.create(EErrorCode.cashFiled);
            } else {
                Map<String, Object> map = new HashMap<>(1);
                map.put("cashId", String.valueOf(oaDCashWithdrawal.getWithdrawalId()));
                map.put("isSuccess", result);

                return Rv.wrap(map);
            }
        } else {
            throw PangException.create(EErrorCode.cashFiled);
        }
    }

    /**
     * 清除司机提现次数
     */
    @Override
    public void clearDriverCashWithdrawal() {

        QueryWrapper<OaDWallet> oaDWalletQueryWrapper = new QueryWrapper<>();
        oaDWalletQueryWrapper.gt(OaDWallet.CASH_COUNT, 0);
        oaDWalletQueryWrapper.select(OaDWallet.WALLET_ID, OaDWallet.VERSION);

        List<OaDWallet> oaDWallets = oaDWalletMapper.selectList(oaDWalletQueryWrapper);

        Date now = new Date();

        // 设置初始值
        for (OaDWallet oaDWallet : oaDWallets) {
            oaDWallet.setCashCount(0);
            oaDWallet.setVersion(oaDWallet.getVersion());
            oaDWallet.setUpdateUser(1L);
            oaDWallet.setUpdateTime(now);
        }

        boolean result = false;

        if (CheckUtil.collectionIsNotEmpty(oaDWallets)) {
            result = iOaDWalletService.updateBatchById(oaDWallets);
        }

        if (!result) {
            log.error("---------------------------------------------------------------------------------");
            log.error("---------------o(︶︿︶)o--司机可提现次数清除失败------------------------------");
            log.error("--------------------------------------------------------------------------------");
            if (oaDWallets.size() == 0) {
                log.error("----------o(∩_∩)o ---因为没有可以清除的司机-------------------------------------------");
            }
        } else {
            log.info("----------o(∩_∩)o --------------司机可提现次数清除成功-------------------------------------------");
        }

    }
}
